Skip to content

chore: release 0.1.9#10

Merged
siy merged 5 commits intomainfrom
release-0.1.9
Jan 9, 2026
Merged

chore: release 0.1.9#10
siy merged 5 commits intomainfrom
release-0.1.9

Conversation

@siy
Copy link
Owner

@siy siy commented Jan 9, 2026

Summary

  • Comprehensive JBCT compliance fixes
  • Test count: 308 passing tests

Changes

  • ActionCompiler: instance-level counter, Option for getClassBytes, resource leak fix, security docs
  • PegEngine: defensive copy for actions map, Option-based null handling, hot path optimizations
  • ParseMode: converted from record to class (mutable context holder)
  • ParsingContext: StringBuilder for furthestExpected, Option for recoveryStartPos, LRU bounded packrat cache (10k entries)
  • GrammarLexer: input size limit (1M chars), StringBuilder capacity hints
  • ParserGenerator: buffer capacity hints, recursion depth limit
  • SemanticValues: defensive copy for values(), safe parsing methods using pragmatica-lite Number

Test plan

  • All 308 tests pass
  • Compilation successful

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added safe numeric parsing helpers for semantic values and made value lists immutable.
    • Added recursion-depth and input-size guards to protect against oversized/too-deep grammars.
    • Introduced bounded parsing cache for more predictable memory usage.
  • Bug Fixes

    • Improved error propagation and diagnostic reporting.
    • Strengthened defensive handling of optional values and token captures.
    • Safer resource handling when compiling/loading generated code.
  • Chores

    • Bumped project/module to v0.1.9 and updated pragmatica-lite to 0.9.10; README examples updated.
  • Tests

    • Test count updated to 308 passing.

✏️ Tip: You can customize this high-level summary in your review settings.

siy and others added 4 commits January 9, 2026 07:37
- SemanticValues: defensive copy in values(), add safe parsing methods
- GrammarParser/ActionCompiler: replace fold() abuse with pattern matching
- ActionCompiler: Option return type, fix resource leak, add security docs
- PegEngine: extract lambda, optimize skipWhitespace allocation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ActionCompiler: instance-level counter instead of static
- PegEngine: defensive copy for actions map, Option for null handling
- ParseMode: convert from record to class (mutable context holder)
- ParsingContext: StringBuilder for furthestExpected, Option for
  recoveryStartPos, LRU bounded packrat cache (10k entries)
- GrammarLexer: input size limit (1M), StringBuilder capacity hints
- ParserGenerator: buffer capacity hints, recursion depth limit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

This PR updates dependency versions and documentation, and makes multiple internal refactors: replaces nulls with Option/Result patterns, adds runtime/input bounds and recursion guards, converts ParseMode from a record to a mutable class, and adjusts packrat caching, error propagation, and resource handling across parser components.

Changes

Cohort / File(s) Summary
Version & Configuration
CHANGELOG.md, README.md, pom.xml
Bumped project/module version to 0.1.9; updated pragmatica-lite from 0.9.0 to 0.9.10 and peglib example to 0.1.9.
Documentation / Meta
CLAUDE.md
Added an "Agent Usage" directive and updated test counts from 305/268 to 308/308.
Action compilation & classloading
src/main/.../action/ActionCompiler.java, .../action/InMemoryFileManager*, .../action/InMemoryClassLoader*
Replaced static class-name counter with per-instance AtomicInteger, use Option<byte[]> for class bytes, improved error propagation with Result.Failure pattern-matching, and adopted try-with-resources for file manager.
Semantic values parsing
src/main/java/org/pragmatica/peg/action/SemanticValues.java
Added safe numeric parsing APIs: toIntSafe(), toLongSafe(), toDoubleSafe() returning Result<T>; values() now returns immutable copy.
Parser generation & recursion guards
src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
Added INITIAL_BUFFER_SIZE and MAX_RECURSION_DEPTH; pre-sized buffers and runtime recursion-depth checks in code generation.
Lexer input & buffer bounds
src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
Added MAX_INPUT_SIZE validation and DEFAULT_TOKEN_CAPACITY for StringBuilder pre-sizing across token scanning methods.
Grammar parsing error propagation
src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
Switched failure handling to Result.Failure<?> instanceof checks and propagate underlying causes in several parse paths.
Parse mode redesign
src/main/java/org/pragmatica/peg/parser/ParseMode.java
Converted public record into a mutable final class with private constructor, added factory methods (standard(), withActions(), noWhitespace()), getters, addValue, setTokenCapture, and childMode().
Parsing context & caching
src/main/java/org/pragmatica/peg/parser/ParsingContext.java
Introduced bounded packrat cache with eviction (MAX_CACHE_SIZE), encoded packrat key layout, switched furthestExpected to StringBuilder, and moved recoveryStartPos to Option<Integer>.
Engine null-safety & diagnostics
src/main/java/org/pragmatica/peg/parser/PegEngine.java
Defensive copy of actions map, widespread use of Option for optional values (token capture, longest match), introduced toDiagnosticsResult helper, and adjusted parse methods to Option semantics.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • chore: release 0.1.8 #9: Overlapping Option-based refactor and failure-tracking improvements touching ParserGenerator and ParsingContext.
  • Release 0.1.7 #8: Prior JBCT-style refactor affecting ParseMode, ParsingContext, and Option adoption patterns.
  • Release 0.1.6 #7: Earlier packrat cache and ParsingContext changes that this PR further refines.

Poem

🐇 I hopped through code and found a trace,
Options tucked in every place,
Guards keep depth and inputs light,
I parsed the night and parsed it right.
No nulls to scare a rabbit's heart—hip, hop, delight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main purpose of this pull request: a release version bump to 0.1.9 with comprehensive improvements and bug fixes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java (1)

1-380: Fix JBCT formatting (CI is red).

CI reports “JBCT formatting issue detected: file not properly formatted.” Please run the formatter on this file to unblock the pipeline.

src/main/java/org/pragmatica/peg/generator/ParserGenerator.java (1)

1-3214: Fix JBCT formatting (CI is red).

CI reports “JBCT formatting issue detected: file not properly formatted.” Please run the formatter on this file to unblock the pipeline.

src/main/java/org/pragmatica/peg/action/ActionCompiler.java (1)

1-263: Fix JBCT formatting (CI is red).

CI reports “JBCT formatting issue detected: file not properly formatted.” Please run the formatter on this file to unblock the pipeline.

src/main/java/org/pragmatica/peg/parser/ParsingContext.java (1)

1-394: Fix JBCT formatting (CI is red).

CI reports “JBCT formatting issue detected: file not properly formatted.” Please run the formatter on this file to unblock the pipeline.

src/main/java/org/pragmatica/peg/parser/PegEngine.java (1)

1-1233: Fix JBCT formatting (CI is red).

CI reports “JBCT formatting issue detected: file not properly formatted.” Please run the formatter on this file to unblock the pipeline.

src/main/java/org/pragmatica/peg/parser/ParseMode.java (1)

1-114: Fix JBCT formatting (CI is red).

CI reports “JBCT formatting issue detected: file not properly formatted.” Please run the formatter on this file to unblock the pipeline.

🤖 Fix all issues with AI agents
In @pom.xml:
- Line 9: Update the pragmatica-lite:core dependency version in pom.xml from
0.9.10 to 0.9.0; locate the <version> element under the pragmatica-lite:core
dependency declaration and change its value to "0.9.0" so the only runtime
dependency matches the coding guideline.

In @src/main/java/org/pragmatica/peg/action/ActionCompiler.java:
- Around line 239-242: The current getClassBytes method uses
map(ByteArrayJavaFileObject::getBytes) which can yield an Option containing null
bytes; replace the map with flatMap and re-wrap the result via Option.option to
guard against null (e.g., flatMap(obj -> Option.option(obj.getBytes()))). Make
the same change for the similar code block at the other occurrence (lines
254-261) so ByteArrayJavaFileObject.getBytes() is always null-checked before
returning an Option used by defineClass.
- Around line 62-64: The current ActionCompiler invocation passes null for the
DiagnosticListener and uses a StringWriter for diagnostics so compilation errors
are dropped; replace that flow by creating a
DiagnosticCollector<JavaFileObject>, pass it as the third argument to
compiler.getTask(...) (instead of null), remove the StringWriter-based
diagnostics, and when returning Result.failure in the compilation branch (e.g.,
in the code handling Result.Failure<?> f and the compile task around lines
158–167 and the failure at line ~164) build the failure message from the
DiagnosticCollector's diagnostics to include compiler errors/warnings.

In @src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java:
- Around line 13-15: The current tokenize() method throws
IllegalArgumentException when input exceeds MAX_INPUT_SIZE, which breaks the
Result-based parsing flow; instead, modify tokenize() to never throw for
oversized input but to emit a GrammarToken.Error token (or sequence) indicating
the oversize condition (use the existing GrammarToken.Error variant), so
GrammarParser.parse() continues to return a Result<Grammar> and can map that
token to a ParseError; update any loop or early-return paths in tokenize() (and
places referencing DEFAULT_TOKEN_CAPACITY if relevant) to push a
GrammarToken.Error with an appropriate message/context and then stop
tokenization rather than throwing an exception.

In @src/main/java/org/pragmatica/peg/grammar/GrammarParser.java:
- Around line 52-54: Run the project's Java formatter on
src/main/java/org/pragmatica/peg/grammar/GrammarParser.java (and any other
changed files) to fix the JBCT formatting failure, then replace the explicit
instanceof Result.Failure<?> checks that call Result.failure(f.cause()) with
Result combinators to avoid unwrap/duplicate error plumbing: locate the blocks
using "result instanceof Result.Failure<?> f" (occurrences around the current
checks at lines 52-54, 62-64 and 113-115), and refactor them to use
result.map(...) or result.flatMap(...) (or result.mapErr/flatMapErr depending on
API) so that success values are transformed and failure causes are propagated
automatically rather than unwrapping and re-wrapping the error.
🧹 Nitpick comments (4)
CHANGELOG.md (1)

8-13: Consider documenting internal improvements in the changelog.

The changelog only mentions the dependency update, but the PR objectives describe substantial internal changes including:

  • Performance optimizations (hot-path allocations in PegEngine)
  • Safety improvements (defensive copies, resource leak fixes)
  • Bounded caches (ParsingContext with 10k entry LRU)
  • Input validation (GrammarLexer 1M character limit)
  • API enhancements (SemanticValues safe parsing methods)

While these may be internal changes, documenting them helps users understand performance characteristics and provides transparency for a release labeled "comprehensive JBCT compliance fixes."

src/main/java/org/pragmatica/peg/generator/ParserGenerator.java (1)

385-387: Recursion-depth guard: include rule/expression context (and confirm “indent” is the intended metric).

Throwing is fine for a generator, but the current exception won’t tell users which rule/expression is too deep, and indent is an indirect proxy for nesting. Consider threading the current rule name (and maybe expr kind) into the message.

Also applies to: 2119-2121

src/main/java/org/pragmatica/peg/parser/PegEngine.java (1)

165-167: Helper extraction looks good; consider making the diagnostic message less generic.

toDiagnosticsResult() centralizes conversion nicely; optionally use parseError.message() as the primary diagnostic message (instead of "parse error") for better UX.

Also applies to: 172-178

src/main/java/org/pragmatica/peg/parser/ParseMode.java (1)

65-93: Optional: de-duplicate getters vs shouldSkipWhitespace() / shouldCollectActions().

You now expose both skipWhitespace()/collectActions() and shouldSkipWhitespace()/shouldCollectActions(); consider keeping one naming style to reduce surface area.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea79a22 and f52facf.

📒 Files selected for processing (12)
  • CHANGELOG.md
  • CLAUDE.md
  • README.md
  • pom.xml
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/action/SemanticValues.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
🧰 Additional context used
📓 Path-based instructions (9)
pom.xml

📄 CodeRabbit inference engine (CLAUDE.md)

Use pragmatica-lite:core 0.9.0 as the only runtime dependency, providing Result/Option/Promise types

Files:

  • pom.xml
**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.java: Use sealed interfaces for abstract types with fixed implementations (Expression, ParseResult, CstNode, AstNode, Trivia, ParseError)
Use record classes for immutable data types (Rule, Grammar, SourceLocation, SourceSpan, ParserConfig)

Files:

  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/SemanticValues.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
src/main/java/org/pragmatica/peg/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

src/main/java/org/pragmatica/peg/**/*.java: Package code under org.pragmatica.peg namespace
Use Result/Option types from pragmatica-lite for return values instead of exceptions or null

Files:

  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/SemanticValues.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
src/main/java/org/pragmatica/peg/parser/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Implement both CST (Concrete Syntax Tree) and AST (Abstract Syntax Tree) output modes for parsers

Files:

  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
src/main/java/org/pragmatica/peg/{parser,generator}/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Support both runtime compilation (JDK Compiler API with full Java support) and source generation (single self-contained Java file) modes

Files:

  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
src/main/java/org/pragmatica/peg/parser/ParsingContext.java

📄 CodeRabbit inference engine (CLAUDE.md)

Use packrat memoization for parsing performance optimization with configurable enable/disable

Files:

  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
**/*[Gg]rammar*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Inline Java actions must be written in { } blocks within grammar syntax and have access to SemanticValues (sv) with $0, $1, $2 references

Files:

  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
src/main/java/org/pragmatica/peg/grammar/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Implement grammar syntax compatible with cpp-peglib, including operators (e1 e2, e1/e2, e*, e+, e?, &e, !e), extensions (< >, ~e, 'text'i, $name, ^), and directives (%whitespace)

Files:

  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
src/main/java/org/pragmatica/peg/generator/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Generated parsers should only depend on pragmatica-lite:core, with optional ErrorReporting enum (BASIC/ADVANCED) for Rust-style diagnostics

Files:

  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/test/java/org/pragmatica/peg/**/*.java : Test coverage should include: grammar parser (17), parsing engine (29), actions (6), generator (18), internal types (24), examples (135), and trivia handling (19)
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Package code under org.pragmatica.peg namespace
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/grammar/**/*.java : Implement grammar syntax compatible with cpp-peglib, including operators (e1 e2, e1/e2, e*, e+, e?, &e, !e), extensions (< >, ~e, 'text'i, $name, ^), and directives (%whitespace)
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Use Result/Option types from pragmatica-lite for return values instead of exceptions or null
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/{parser,generator}/**/*.java : Support both runtime compilation (JDK Compiler API with full Java support) and source generation (single self-contained Java file) modes
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to pom.xml : Use pragmatica-lite:core 0.9.0 as the only runtime dependency, providing Result/Option/Promise types
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/generator/**/*.java : Generated parsers should only depend on pragmatica-lite:core, with optional ErrorReporting enum (BASIC/ADVANCED) for Rust-style diagnostics
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/parser/**/*.java : Implement both CST (Concrete Syntax Tree) and AST (Abstract Syntax Tree) output modes for parsers
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Package code under org.pragmatica.peg namespace

Applied to files:

  • README.md
  • pom.xml
  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to pom.xml : Use pragmatica-lite:core 0.9.0 as the only runtime dependency, providing Result/Option/Promise types

Applied to files:

  • README.md
  • pom.xml
  • CHANGELOG.md
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/generator/**/*.java : Generated parsers should only depend on pragmatica-lite:core, with optional ErrorReporting enum (BASIC/ADVANCED) for Rust-style diagnostics

Applied to files:

  • README.md
  • pom.xml
  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/grammar/**/*.java : Implement grammar syntax compatible with cpp-peglib, including operators (e1 e2, e1/e2, e*, e+, e?, &e, !e), extensions (< >, ~e, 'text'i, $name, ^), and directives (%whitespace)

Applied to files:

  • README.md
  • pom.xml
  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Use Result/Option types from pragmatica-lite for return values instead of exceptions or null

Applied to files:

  • README.md
  • pom.xml
  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/action/SemanticValues.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/{parser,generator}/**/*.java : Support both runtime compilation (JDK Compiler API with full Java support) and source generation (single self-contained Java file) modes

Applied to files:

  • README.md
  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/parser/**/*.java : Implement both CST (Concrete Syntax Tree) and AST (Abstract Syntax Tree) output modes for parsers

Applied to files:

  • README.md
  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/test/java/org/pragmatica/peg/**/*.java : Test coverage should include: grammar parser (17), parsing engine (29), actions (6), generator (18), internal types (24), examples (135), and trivia handling (19)

Applied to files:

  • README.md
  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/error/**/*.java : Support configurable error recovery with three strategies: NONE (fail immediately), BASIC (report error with context), ADVANCED (continue parsing and collect multiple errors)

Applied to files:

  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/grammar/Expression.java : Implement cut operator (^ or ↑) to commit to current choice and prevent backtracking

Applied to files:

  • CLAUDE.md
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/parser/ParsingContext.java : Use packrat memoization for parsing performance optimization with configurable enable/disable

Applied to files:

  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/error/Diagnostic.java : Implement Rust-style diagnostic formatting with error location (file:line:column), context lines, and help messages for error recovery output

Applied to files:

  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to **/*.java : Use record classes for immutable data types (Rule, Grammar, SourceLocation, SourceSpan, ParserConfig)

Applied to files:

  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/tree/Trivia.java : Support trivia classification by content inspection: lines starting with // are LineComment, /* ... */ are BlockComment, otherwise Whitespace

Applied to files:

  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/tree/**/*.java : Group whitespace and comments as Trivia nodes (Trivia.Whitespace, Trivia.LineComment, Trivia.BlockComment) for lossless CST

Applied to files:

  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/test/java/org/pragmatica/peg/examples/Java25GrammarExample.java : For Java 25 grammar implementation, distinguish between hard keywords (always reserved) and contextual keywords (context-dependent), matching contextual keywords in specific rules only

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to **/*[Gg]rammar*.java : Inline Java actions must be written in { } blocks within grammar syntax and have access to SemanticValues (sv) with $0, $1, $2 references

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
🧬 Code graph analysis (1)
src/main/java/org/pragmatica/peg/parser/PegEngine.java (1)
src/main/java/org/pragmatica/peg/action/SemanticValues.java (1)
  • SemanticValues (14-190)
🪛 GitHub Actions: CI
src/main/java/org/pragmatica/peg/parser/ParsingContext.java

[error] 1-1: JBCT formatting issue detected: file not properly formatted.

src/main/java/org/pragmatica/peg/grammar/GrammarParser.java

[error] 1-1: JBCT formatting issue detected: file not properly formatted.

src/main/java/org/pragmatica/peg/parser/ParseMode.java

[error] 1-1: JBCT formatting issue detected: file not properly formatted.

src/main/java/org/pragmatica/peg/parser/PegEngine.java

[error] 1-1: JBCT formatting issue detected: file not properly formatted.

src/main/java/org/pragmatica/peg/generator/ParserGenerator.java

[error] 1-1: JBCT formatting issue detected: file not properly formatted.

src/main/java/org/pragmatica/peg/action/ActionCompiler.java

[error] 1-1: JBCT formatting issue detected: file not properly formatted.

src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java

[error] 1-1: JBCT formatting issue detected: file not properly formatted.

🔇 Additional comments (20)
README.md (1)

25-25: LGTM!

The version update in the dependency example is consistent with the version bump in pom.xml and CHANGELOG.md.

src/main/java/org/pragmatica/peg/action/SemanticValues.java (3)

65-87: Safe parsing methods improve error handling.

The addition of toIntSafe(), toLongSafe(), and toDoubleSafe() methods provides Result-based alternatives to the exception-throwing methods, aligning with the project's JBCT compliance goals and the guideline to use Result/Option types.

The methods properly delegate to Number.parseInt/parseLong/parseDouble from pragmatica-lite after trimming the input.

Based on learnings about using Result/Option types from pragmatica-lite for return values instead of exceptions.


169-174: Defensive copy preserves immutability.

Returning List.copyOf(values) instead of the internal list prevents external mutation and aligns with the immutability goals mentioned in the PR objectives.


4-5: pragmatica-lite:core 0.9.10 is not available on Maven Central and will cause a build failure.

The pom.xml declares pragmatica-lite.version=0.9.10, but Maven Central only publishes versions up to 0.8.x. No custom repository is configured in pom.xml to provide 0.9.10, so the build will fail during dependency resolution. The CHANGELOG indicates this was an intentional upgrade (v0.1.9), but the artifact doesn't exist in any public repository.

Clarify whether:

  1. pragmatica-lite 0.9.10 will be published (and when)
  2. A custom repository should be added to pom.xml to resolve it
  3. The version should revert to an available release (e.g., 0.9.0)

The Number API verification cannot proceed until this dependency is resolved.

CLAUDE.md (2)

5-7: Agent usage directive added.

The new section mandates using only the jbct-coder agent for all coding tasks. This is a project-specific workflow guideline with no impact on code functionality.


151-151: Test count updated to reflect current state.

The test count has been updated from 305 to 308, which aligns with the PR objectives stating "308 passing tests."

Also applies to: 422-422

src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java (1)

85-90: StringBuilder capacity hints look good.

Reasonable micro-optimization; still safe since builders grow as needed.

Also applies to: 95-100, 104-105, 135-136, 173-175, 202-205, 218-224

src/main/java/org/pragmatica/peg/generator/ParserGenerator.java (1)

12-14: Buffer pre-sizing looks good.

Using a larger initial StringBuilder capacity for generated sources is a sensible perf win for non-trivial grammars.

Also applies to: 118-119, 135-136

src/main/java/org/pragmatica/peg/action/ActionCompiler.java (3)

25-33: Security documentation addition is a good call.

Clear warning about arbitrary code execution risk is important for this component.


38-39: Instance-scoped action class naming is safer than a static counter.

Avoids cross-test/process interference and makes ActionCompiler behavior easier to reason about.

Also applies to: 94-100


152-176: Confirm Java toolchain expectations for --release 25.

This will fail at runtime on older JDKs even if the library is otherwise usable. If Java 25 is required for the project, great—otherwise consider making the release level configurable or documenting it more explicitly.

src/main/java/org/pragmatica/peg/parser/ParsingContext.java (3)

21-23: Bounded LRU packrat cache is a good safety improvement.

Capping to MAX_CACHE_SIZE prevents unbounded memory growth while keeping recent entries hot. Based on learnings/guidelines about packrat memoization, this is a solid default.

Also applies to: 47-57, 362-369


42-43: recoveryStartPos is now Option-wrapped: ensure it’s used or remove it.

In this file it’s set/cleared but not otherwise referenced; please confirm it’s consumed elsewhere for error nodes/diagnostics (or drop it to avoid dead state).

Also applies to: 222-227, 232-235


36-37: This concern is not applicable to this codebase.

The project targets Java 25 (maven.compiler.release=25 in pom.xml), and StringBuilder.isEmpty() has been available since Java 15. The current code using isEmpty() is the correct, more readable approach—length() == 0 would be an unnecessary downgrade.

Likely an incorrect or invalid review comment.

src/main/java/org/pragmatica/peg/parser/PegEngine.java (5)

36-48: Defensive copy of actions map is the right call.

Map.copyOf(actions) prevents caller mutation from affecting engine behavior; Map.of() in createWithoutActions() also avoids accidental mutability.


316-325: Option-based token/action handling looks good.

This aligns well with the project’s Option/Result style and avoids null checks.


458-470: Dictionary match refactor to Option is solid.

Makes “no match” explicit and removes null tracking.

Also applies to: 478-483


747-752: Whitespace fast-path improvement looks good.

Early List.of() return avoids unnecessary allocations on hot paths.


889-891: Token-capture propagation via Option.onPresent is a nice cleanup.

Keeps the “only on success” semantics clear and avoids manual null checks.

Also applies to: 935-937, 997-999, 1079-1081

src/main/java/org/pragmatica/peg/parser/ParseMode.java (1)

16-33: ParseMode as a mutable context holder is consistent with how it’s used.

Factories + childMode() + Option-guarded mutation read well and match the intended semantics.

Also applies to: 65-79, 97-103, 107-113

<groupId>org.pragmatica-lite</groupId>
<artifactId>peglib</artifactId>
<version>0.1.8</version>
<version>0.1.9</version>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n pom.xml | head -60

Repository: siy/java-peglib

Length of output: 2543


🏁 Script executed:

# Search for all dependency declarations in pom.xml
rg -A 3 "<dependency>" pom.xml

Repository: siy/java-peglib

Length of output: 547


🌐 Web query:

pragmatica-lite 0.9.10 maven central release

💡 Result:

I couldn't find pragmatica-lite version 0.9.10 on Maven Central. The Maven Central group listing and package pages show other versions (e.g. tcp 0.9.8, core up to ~0.9.0 / 0.8.x), but no 0.9.10 release. [1][2][3]

Sources:

  • Maven Central group index for org.pragmatica-lite. [1]
  • mvnrepository listing for org.pragmatica-lite tcp (shows 0.9.8). [2]
  • javadoc.io / core package (latest shown ~0.9.0). [3]

Want me to watch for a 0.9.10 release and notify you when it appears?


🌐 Web query:

pragmatica-lite releases changelog 0.9.0 0.9.10

💡 Result:

Do you mean the pragmatica-lite "pragmatica-lite" artifact (or a specific module like core, tcp, etc.) — and do you want the full changelog entries for versions 0.9.0 and 0.9.10 or just a short summary?


🏁 Script executed:

#!/bin/bash
# Query Maven Central for pragmatica-lite:core versions
echo "Checking Maven Central for org.pragmatica-lite:core versions:"
curl -s "https://search.maven.org/solrsearch/select?q=g:org.pragmatica-lite+AND+a:core&core=gav&rows=100&wt=json" | jq '.response.docs[] | {v: .v}' | sort -u

Repository: siy/java-peglib

Length of output: 120


🏁 Script executed:

#!/bin/bash
# Also check the GitHub releases for pragmatica-lite project
echo "Searching for pragmatica-lite releases:"
curl -s https://api.github.com/repos/siy/pragmatica-lite/releases 2>/dev/null | jq '.[] | {tag_name, published_at}' | head -40

Repository: siy/java-peglib

Length of output: 720


Update pragmatica-lite:core dependency version to 0.9.0 per coding guideline.

The pom.xml specifies pragmatica-lite:core 0.9.10, but the coding guideline requires version 0.9.0 as the only runtime dependency. While 0.9.10 has been released (2026-01-07), the dependency version must align with the stated requirement.

pragmatica-lite:core is correctly the only runtime dependency; only the version number requires adjustment.

🤖 Prompt for AI Agents
In @pom.xml at line 9, Update the pragmatica-lite:core dependency version in
pom.xml from 0.9.10 to 0.9.0; locate the <version> element under the
pragmatica-lite:core dependency declaration and change its value to "0.9.0" so
the only runtime dependency matches the coding guideline.

Comment on lines 62 to 64
if (result instanceof Result.Failure<?> f) {
return Result.failure(f.cause());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n src/main/java/org/pragmatica/peg/action/ActionCompiler.java | sed -n '50,75p'

Repository: siy/java-peglib

Length of output: 1016


🏁 Script executed:

cat -n src/main/java/org/pragmatica/peg/action/ActionCompiler.java | sed -n '150,180p'

Repository: siy/java-peglib

Length of output: 1841


🏁 Script executed:

head -20 src/main/java/org/pragmatica/peg/action/ActionCompiler.java

Repository: siy/java-peglib

Length of output: 684


🏁 Script executed:

cat > /tmp/check_compiler_api.py << 'EOF'
# Check Java Compiler API documentation
# The getTask method signature is:
# CompilationTask getTask(Writer out, JavaFileManager fileManager,
#                         DiagnosticListener<? super JavaFileObject> diagnosticListener,
#                         Iterable<String> options, Iterable<String> classes,
#                         Iterable<? extends JavaFileObject> compilationUnits)

# Parameter meanings:
# 1. Writer out - for non-diagnostic output (like verbose logging)
# 2. fileManager
# 3. DiagnosticListener - THIS is where compilation diagnostics (errors/warnings) go
# 4. options
# 5. classes
# 6. compilationUnits

# The issue: In the code, the StringWriter is passed as 'out' (parameter 1)
# But the DiagnosticListener parameter (parameter 3) is null
# This means diagnostics are dropped/not captured

print("""
Java Compiler API Analysis:
==========================

compiler.getTask() signature:
  CompilationTask getTask(
    Writer out,                                    // <- StringWriter passed here (WRONG)
    JavaFileManager fileManager,
    DiagnosticListener<? super JavaFileObject> diagnosticListener,  // <- null here (PROBLEM)
    Iterable<String> options,
    Iterable<String> classes,
    Iterable<? extends JavaFileObject> compilationUnits)

Current code (INCORRECT):
  compiler.getTask(diagnostics, fileManager, null, ...)
  - Passes StringWriter as 'out' (for general output, not diagnostics)
  - Passes null for DiagnosticListener (where actual compilation errors go)
  
Result: Compilation errors/warnings are NOT captured properly

Solution:
  Use DiagnosticCollector<JavaFileObject> for the DiagnosticListener parameter
  Pass null or discard the 'out' parameter
  
  DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
  compiler.getTask(null, fileManager, collector, ...)
  // Then use collector.getDiagnostics() to get errors/warnings
""")
EOF
python /tmp/check_compiler_api.py

Repository: siy/java-peglib

Length of output: 145


🏁 Script executed:

rg -A 5 "^import.*javax.tools" src/main/java/org/pragmatica/peg/action/ActionCompiler.java

Repository: siy/java-peglib

Length of output: 321


🏁 Script executed:

rg "DiagnosticCollector" src/main/java/org/pragmatica/peg/

Repository: siy/java-peglib

Length of output: 41


🏁 Script executed:

cat -n src/main/java/org/pragmatica/peg/action/ActionCompiler.java | sed -n '152,177p'

Repository: siy/java-peglib

Length of output: 1701


🏁 Script executed:

# Check if the compileAction method itself has similar issues
cat -n src/main/java/org/pragmatica/peg/action/ActionCompiler.java | sed -n '74,150p'

Repository: siy/java-peglib

Length of output: 3746


Replace StringWriter diagnostics capture with DiagnosticCollector for proper compilation error reporting.

The compiler.getTask() method's first parameter is the general out stream, not a diagnostics sink. The third parameter is where DiagnosticListener should be passed to capture compilation errors and warnings. Currently, null is passed, meaning all diagnostics are dropped. When compilation fails at line 164, the error message will be nearly empty (just the StringWriter's content, which has nothing).

Use DiagnosticCollector<JavaFileObject> instead:

Required fix
+import javax.tools.DiagnosticCollector;
 ...
         try (var standardFileManager = compiler.getStandardFileManager(null, null, null)) {
             var fileManager = new InMemoryFileManager(standardFileManager);
             var sourceFile = new StringJavaFileObject(className, sourceCode);
-            var diagnostics = new StringWriter();
+            var collector = new DiagnosticCollector<JavaFileObject>();
             var task = compiler.getTask(
-                diagnostics, fileManager, null, List.of("--release", "25"), null, List.of(sourceFile));
+                null, fileManager, collector, List.of("--release", "25"), null, List.of(sourceFile));
             if (!task.call()) {
                 return Result.failure(new ParseError.SemanticError(
-                    location, "Action compilation failed: " + diagnostics));
+                    location, "Action compilation failed: " + collector.getDiagnostics()));
             }

Also applies to: 158–167

🤖 Prompt for AI Agents
In @src/main/java/org/pragmatica/peg/action/ActionCompiler.java around lines 62
- 64, The current ActionCompiler invocation passes null for the
DiagnosticListener and uses a StringWriter for diagnostics so compilation errors
are dropped; replace that flow by creating a
DiagnosticCollector<JavaFileObject>, pass it as the third argument to
compiler.getTask(...) (instead of null), remove the StringWriter-based
diagnostics, and when returning Result.failure in the compilation branch (e.g.,
in the code handling Result.Failure<?> f and the compile task around lines
158–167 and the failure at line ~164) build the failure message from the
DiagnosticCollector's diagnostics to include compiler errors/warnings.

Comment on lines 239 to 242
Option<byte[]> getClassBytes(String className) {
return Option.option(classFiles.get(className))
.map(ByteArrayJavaFileObject::getBytes);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Harden Option<byte[]> so null bytes can’t slip through.

If ByteArrayJavaFileObject.getBytes() is still null, map(ByteArrayJavaFileObject::getBytes) may produce an Option that unwraps to null (depending on Option semantics), which would blow up in defineClass. Prefer flatMap to re-wrap via Option.option(...).

Proposed fix
 Option<byte[]> getClassBytes(String className) {
-    return Option.option(classFiles.get(className))
-                 .map(ByteArrayJavaFileObject::getBytes);
+    return Option.option(classFiles.get(className))
+                 .flatMap(file -> Option.option(file.getBytes()));
 }

Also applies to: 254-261

🤖 Prompt for AI Agents
In @src/main/java/org/pragmatica/peg/action/ActionCompiler.java around lines 239
- 242, The current getClassBytes method uses
map(ByteArrayJavaFileObject::getBytes) which can yield an Option containing null
bytes; replace the map with flatMap and re-wrap the result via Option.option to
guard against null (e.g., flatMap(obj -> Option.option(obj.getBytes()))). Make
the same change for the similar code block at the other occurrence (lines
254-261) so ByteArrayJavaFileObject.getBytes() is always null-checked before
returning an Option used by defineClass.

Comment on lines +13 to +15
private static final int MAX_INPUT_SIZE = 1_000_000;
private static final int DEFAULT_TOKEN_CAPACITY = 32;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid throwing in tokenize(): return a lexer error token to keep Result-based flow.

tokenize() throwing IllegalArgumentException will bypass GrammarParser.parse()’s Result<Grammar> contract on oversized inputs. Prefer emitting GrammarToken.Error so the caller can surface a ParseError consistently (as per learnings/guidelines about Result/Option usage).

Proposed fix (keep signature, no exception)
 public static List<GrammarToken> tokenize(String input) {
-    if (input.length() > MAX_INPUT_SIZE) {
-        throw new IllegalArgumentException(
-            "Grammar input exceeds maximum size of " + MAX_INPUT_SIZE + " characters");
-    }
-    return new GrammarLexer(input).tokenizeAll();
+    if (input.length() > MAX_INPUT_SIZE) {
+        var loc = SourceLocation.at(1, 1, 0);
+        var span = SourceSpan.at(loc);
+        return List.of(
+            new GrammarToken.Error(span, "Grammar input exceeds maximum size of " + MAX_INPUT_SIZE + " characters"),
+            new GrammarToken.Eof(span)
+        );
+    }
+    return new GrammarLexer(input).tokenizeAll();
 }

Also applies to: 29-33

🤖 Prompt for AI Agents
In @src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java around lines 13 -
15, The current tokenize() method throws IllegalArgumentException when input
exceeds MAX_INPUT_SIZE, which breaks the Result-based parsing flow; instead,
modify tokenize() to never throw for oversized input but to emit a
GrammarToken.Error token (or sequence) indicating the oversize condition (use
the existing GrammarToken.Error variant), so GrammarParser.parse() continues to
return a Result<Grammar> and can map that token to a ParseError; update any loop
or early-return paths in tokenize() (and places referencing
DEFAULT_TOKEN_CAPACITY if relevant) to push a GrammarToken.Error with an
appropriate message/context and then stop tokenization rather than throwing an
exception.

Comment on lines 52 to 54
if (result instanceof Result.Failure<?> f) {
return Result.failure(f.cause());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix JBCT formatting (CI is red) + consider avoiding unwrap() via Result combinators.

  • CI reports “JBCT formatting issue detected: file not properly formatted.” Please run the formatter on this file (and any other touched files) to unblock the pipeline.
  • The new instanceof Result.Failure<?> f propagation is fine, but these blocks can usually become return result.map(...) / flatMap(...) to avoid unwrap() and duplicate error plumbing.

Also applies to: 62-64, 113-115

🤖 Prompt for AI Agents
In @src/main/java/org/pragmatica/peg/grammar/GrammarParser.java around lines 52
- 54, Run the project's Java formatter on
src/main/java/org/pragmatica/peg/grammar/GrammarParser.java (and any other
changed files) to fix the JBCT formatting failure, then replace the explicit
instanceof Result.Failure<?> checks that call Result.failure(f.cause()) with
Result combinators to avoid unwrap/duplicate error plumbing: locate the blocks
using "result instanceof Result.Failure<?> f" (occurrences around the current
checks at lines 52-54, 62-64 and 113-115), and refactor them to use
result.map(...) or result.flatMap(...) (or result.mapErr/flatMapErr depending on
API) so that success values are transformed and failure causes are propagated
automatically rather than unwrapping and re-wrapping the error.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java (1)

29-32: Consider Result pattern for consistency.

The input size validation is effective. However, based on learnings, the codebase prefers Result/Option types over exceptions. Consider returning Result<List<GrammarToken>, String> to align with this pattern, though the current implementation is functional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f52facf and 31097d0.

📒 Files selected for processing (7)
  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/main/java/org/pragmatica/peg/generator/ParserGenerator.java
  • src/main/java/org/pragmatica/peg/parser/PegEngine.java
  • src/main/java/org/pragmatica/peg/parser/ParseMode.java
  • src/main/java/org/pragmatica/peg/parser/ParsingContext.java
🧰 Additional context used
📓 Path-based instructions (4)
**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.java: Use sealed interfaces for abstract types with fixed implementations (Expression, ParseResult, CstNode, AstNode, Trivia, ParseError)
Use record classes for immutable data types (Rule, Grammar, SourceLocation, SourceSpan, ParserConfig)

Files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
src/main/java/org/pragmatica/peg/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

src/main/java/org/pragmatica/peg/**/*.java: Package code under org.pragmatica.peg namespace
Use Result/Option types from pragmatica-lite for return values instead of exceptions or null

Files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
**/*[Gg]rammar*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Inline Java actions must be written in { } blocks within grammar syntax and have access to SemanticValues (sv) with $0, $1, $2 references

Files:

  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
src/main/java/org/pragmatica/peg/grammar/**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

Implement grammar syntax compatible with cpp-peglib, including operators (e1 e2, e1/e2, e*, e+, e?, &e, !e), extensions (< >, ~e, 'text'i, $name, ^), and directives (%whitespace)

Files:

  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Package code under org.pragmatica.peg namespace
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/test/java/org/pragmatica/peg/**/*.java : Test coverage should include: grammar parser (17), parsing engine (29), actions (6), generator (18), internal types (24), examples (135), and trivia handling (19)
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/grammar/**/*.java : Implement grammar syntax compatible with cpp-peglib, including operators (e1 e2, e1/e2, e*, e+, e?, &e, !e), extensions (< >, ~e, 'text'i, $name, ^), and directives (%whitespace)
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Use Result/Option types from pragmatica-lite for return values instead of exceptions or null
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/{parser,generator}/**/*.java : Support both runtime compilation (JDK Compiler API with full Java support) and source generation (single self-contained Java file) modes
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to pom.xml : Use pragmatica-lite:core 0.9.0 as the only runtime dependency, providing Result/Option/Promise types
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/generator/**/*.java : Generated parsers should only depend on pragmatica-lite:core, with optional ErrorReporting enum (BASIC/ADVANCED) for Rust-style diagnostics
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/{parser,generator}/**/*.java : Support both runtime compilation (JDK Compiler API with full Java support) and source generation (single self-contained Java file) modes

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/test/java/org/pragmatica/peg/**/*.java : Test coverage should include: grammar parser (17), parsing engine (29), actions (6), generator (18), internal types (24), examples (135), and trivia handling (19)

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Use Result/Option types from pragmatica-lite for return values instead of exceptions or null

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/**/*.java : Package code under org.pragmatica.peg namespace

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/generator/**/*.java : Generated parsers should only depend on pragmatica-lite:core, with optional ErrorReporting enum (BASIC/ADVANCED) for Rust-style diagnostics

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/grammar/**/*.java : Implement grammar syntax compatible with cpp-peglib, including operators (e1 e2, e1/e2, e*, e+, e?, &e, !e), extensions (< >, ~e, 'text'i, $name, ^), and directives (%whitespace)

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to **/*[Gg]rammar*.java : Inline Java actions must be written in { } blocks within grammar syntax and have access to SemanticValues (sv) with $0, $1, $2 references

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/error/Diagnostic.java : Implement Rust-style diagnostic formatting with error location (file:line:column), context lines, and help messages for error recovery output

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/grammar/Expression.java : Implement cut operator (^ or ↑) to commit to current choice and prevent backtracking

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/error/**/*.java : Support configurable error recovery with three strategies: NONE (fail immediately), BASIC (report error with context), ADVANCED (continue parsing and collect multiple errors)

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/main/java/org/pragmatica/peg/parser/**/*.java : Implement both CST (Concrete Syntax Tree) and AST (Abstract Syntax Tree) output modes for parsers

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
📚 Learning: 2025-12-30T12:39:57.084Z
Learnt from: CR
Repo: siy/java-peglib PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-30T12:39:57.084Z
Learning: Applies to src/test/java/org/pragmatica/peg/examples/Java25GrammarExample.java : For Java 25 grammar implementation, distinguish between hard keywords (always reserved) and contextual keywords (context-dependent), matching contextual keywords in specific rules only

Applied to files:

  • src/main/java/org/pragmatica/peg/action/ActionCompiler.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java
  • src/main/java/org/pragmatica/peg/grammar/GrammarParser.java
🔇 Additional comments (11)
src/main/java/org/pragmatica/peg/grammar/GrammarLexer.java (2)

13-14: LGTM! Good defensive programming practice.

The constants provide clear resource bounds and capacity hints, aligning with the PR's goal of adding runtime limits and optimizations.


85-85: LGTM! Effective allocation optimization.

The StringBuilder capacity hints reduce reallocation overhead. The 32-character default is appropriate for most token types. Note that action code blocks (Line 173) may frequently exceed this capacity, but the StringBuilder will still resize automatically—this is a minor efficiency consideration rather than a functional concern.

Also applies to: 95-95, 104-104, 135-135, 173-173, 202-202, 218-218

src/main/java/org/pragmatica/peg/grammar/GrammarParser.java (3)

52-54: LGTM: Pattern matching for Result.Failure.

The refactor from isFailure() to instanceof Result.Failure<?> f is idiomatic and consistent with the PR's broader Result handling improvements.


62-64: LGTM: Consistent failure propagation.

Same pattern matching refactor as the directive parsing above.


113-115: LGTM: Uniform Result handling.

Completes the consistent pattern matching refactor across all failure checks in parseGrammar().

src/main/java/org/pragmatica/peg/action/ActionCompiler.java (6)

25-32: Excellent security documentation.

The added warning about arbitrary code execution risks is critical for users working with untrusted grammars. The guidance to use source generation mode for sandboxing is practical and actionable.


38-38: Good encapsulation improvement.

Moving the counter from static to instance-level improves encapsulation and allows multiple ActionCompiler instances to operate independently. Since each compilation creates its own InMemoryClassLoader, potential class name collisions across instances are safely isolated.


62-64: LGTM: Consistent Result.Failure pattern matching.

Aligns with the same refactor applied across other files in this PR.


158-177: Critical resource leak fix.

The try-with-resources block ensures standardFileManager is properly closed, fixing a resource leak present in the previous implementation. The InMemoryFileManager delegates to the underlying manager, so its cleanup is handled correctly.


239-242: Proper Option usage for null safety.

Changing the return type to Option<byte[]> aligns with the coding guidelines and eliminates null handling ambiguity.

Based on learnings, projects should use Result/Option types from pragmatica-lite instead of null.


254-261: Correct Option handling.

The updated findClass properly handles the Option<byte[]> from getClassBytes, checking for presence before unwrapping. The behavior remains correct.

@siy siy merged commit aa45ffb into main Jan 9, 2026
2 checks passed
@siy siy deleted the release-0.1.9 branch January 9, 2026 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant